#ifndef CRENDERMASTER_H_
#define CRENDERMASTER_H_

//////////////////////////////////////
// Headers and Libraries
//////////////////////////////////////

#include "../Config.h"

#include "../SLList.h"
#include "../Asset Manager/AssetManager.h"
#include "../Camera/Camera.h"
#include "../Event System/IListener.h"
// #include "../Game Objects/BaseObject.h"


//////////////////////////////////////
// Pound Defines and Macros
//////////////////////////////////////
#define MAX_RENDER_FUNCS 20
	

//////////////////////////////////////
// Structures
//////////////////////////////////////

// An object that will be rendered
struct TRenderNode
{
	unsigned int nMeshID;
	// Orientation Matrix
	TRenderNode* pNext;

	TRenderNode( void ) { pNext = NULL; }
};


//////////////////////////////////////////////
// CRenderMaster: The master of rendering
class CRenderMaster: public IListener
{
private:
	/////////////////////////////////////
	// Enums
	/////////////////////////////////////
	enum PRIMITIVE{ SHAPE_SPHERE, SHAPE_CYLINDER, SHAPE_MAX };


	//////////////////////////////////////
	// Variables
	//////////////////////////////////////
	// The asset manager
	CAssetManager m_AssetManager;

	// DirectX device and such
	IDirect3D9 * m_pD3D;
	IDirect3DDevice9* m_pDev;

	// An array of vertex declarations
	IDirect3DVertexDeclaration9* m_pVertDeclarations[MAX_RENDER_FUNCS];

	// The shader used that will display a wireframe shape of your desire
	ID3DXEffect* m_pDebugShapes;

	// A vertex declartion stricly for position
	IDirect3DVertexDeclaration9* m_pShapesDecl;

	//////////////////////
	// Sphere
	ID3DXMesh* m_pSphereMesh;
	IDirect3DVertexBuffer9* m_pSphereVerts;
	IDirect3DIndexBuffer9* m_pSphereIndices;
	unsigned int m_unSphereVertSize;
	unsigned int m_unNumSphereVerts;
	unsigned int m_unNumSphereTris;

	////////////////////////
	// Cylinder
	ID3DXMesh* m_pCylinderMesh;
	IDirect3DVertexBuffer9* m_pCylinderVerts;
	IDirect3DIndexBuffer9* m_pCylinderIndices;
	unsigned int m_unCylinderVertSize;
	unsigned int m_unNumCylinderVerts;
	unsigned int m_unNumCylinderTris;


	//////////////////////
	// Deferred Shading
	//
	// How the scene quad's vertices are laid out
	IDirect3DVertexDeclaration9* m_pSceneQuadDecl;

	// Holds the scene quad's verts
	IDirect3DVertexBuffer9* m_pSceneQuadVerts;

	// The render target the color information is rendered to
	IDirect3DTexture9* m_pColorTexture;
	IDirect3DSurface9* m_pColorSurface;

	// The render target the depth information is rendered to
	IDirect3DTexture9* m_pDepthTexture;
	IDirect3DSurface9* m_pDepthSurface;

	// The render target the normal information is rendered to
	IDirect3DTexture9* m_pNormalTexture;
	IDirect3DSurface9* m_pNormalSurface;
	
	// The render target the light information is rendered to
	IDirect3DTexture9* m_pLightTexture;
	IDirect3DSurface9* m_pLightSurface;

	// The shaders used for different lights
	ID3DXEffect* m_pDirectLightShader;
	ID3DXEffect* m_pPointLightShader;

	// A shader which assembles the GBuffer
	ID3DXEffect* m_pPostProcessShader;

	// A shader which clears out the GBuffer
	ID3DXEffect* m_pClearShader;

	// A pointer to the back buffer
	IDirect3DSurface9* m_pBackBuffer;
	//
	// End deferred
	/////////////////////

	// Camera
	CCamera m_Camera;


	//////////////////////////////////////
	// Functions
	//////////////////////////////////////

	// Draws a debug shape
	void RenderShape( D3DXVECTOR3 vPosition, float fRadius, PRIMITIVE shape );

	// An array of render functions 
	void ( CRenderMaster::*RenderFunc[MAX_RENDER_FUNCS] )( TRenderNode* pNode, TMesh* pMesh );

	// Get the handles to a point light's variables
	void InitDebugShapes( void );

	// Sets self up to get events
	void RegisterEvents( void );

	// Un set self up to get events
	void UnregisterEvents( void );


	/////////////////////
	// Deferred Shading
	//
	// Combines the GBuffer for the final image
	void CombineFinalImage( void );

	// Renders all the lights to the light render target
	void RenderLights( void );

	// Applies a directional light to the scene
	void RenderDirectionalLight( D3DXVECTOR3 vLightDir, D3DXVECTOR4 vColor );

	// Applies a point light to the scene
	void RenderPointLight( D3DXVECTOR3 vPosition, D3DXVECTOR4 vColor, float fRadius, float fIntensity );

	// Clears out the GBuffer
	void ClearGBuffer( void );

	// Initialize deferred shading
	void InitDeferred( void );

	// Shutdown deferred shading
	void ShutdownDeferred( void );

	// Load in the shaders
	void InitDeferredShaders( void );

	// Initialize the render targets
	void InitRenderTargets( void );
	//
	// End deferred
	/////////////////////

	// Remove this
	// Bandicoot List
	SLList<class CBaseObject*> m_Bandicoot;

	void InitPractice( void );
	void PracticeRender( void );
	TRenderNode* m_pPracticeRoot;
	IDirect3DVertexDeclaration9* m_pPracticeDecl;
	ID3DXEffect* m_pInsertShaderHere;

	void DRAWTROGDOR( void );
	void GetInput( void );

public:
	//////////////////////////////////////
	// Functions
	//////////////////////////////////////
	CRenderMaster( void );
	~CRenderMaster( void );

	void Shutdown( void );
	void Initialize( HWND hWnd, char* szShaderFile );

	// Renders the objects to the screen
	void Render( TRenderNode* pRootNode );

	// Loads a mesh and returns an index to it
	inline unsigned int LoadMesh( char* szFileName ) { return m_AssetManager.LoadMesh( szFileName ); }

	/// REMOVOEPOVOVEO
	inline unsigned int LoadTROGDOR( const char* szFileName ) { return m_AssetManager.LoadTROGDOR( szFileName ); }

	void ProcessEvent( class CEvent* pEvent );
};


#endif
